﻿#region BSD 3-Clause License
/* Copyright (c) 2012, Intel Corporation
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 *    this list of conditions and the following disclaimer in the documentation
 *    and/or other materials provided with the distribution.
 *    
 * 3. Neither the name of Intel Corporation nor the names of its contributors may
 *    be used to endorse or promote products derived from this software without
 *    specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#endregion

using System;

namespace OpenHopla.Numbers
{
    /// <remarks>
    /// You can't possibly get a good technology going without an enormous
    /// number of failures. It's a universal rule. If you look at bicycles, 
    /// there were thousands of weird models built and tried before they
    /// found the one that really worked. You could never design a bicycle
    /// theoretically. Even now, after we've been building them for 100
    /// years, it's very difficult to understand just why a bicycle
    /// works--it's even difficult to formulate it as a mathematical problem.
    /// But just by trial and error, we found out how to do it, and the error
    /// was essential. The same is true of airplanes.
    /// 
    /// Freeman Dyson in “Freeman Dyson’s Brain” by Stewart Brand
    /// WIRED, Issue 6.02, Feb 1998
    /// http://www.wired.com/wired/archive/6.02/dyson.html (page 7)
    /// </remarks>
    public static class DysonNumbers
    {
        /// <summary>
        /// </summary>
        /// <param name="rightDigit"></param>
        /// <param name="carryDigit"></param>
        /// <param name="n"></param>
        /// <returns></returns>
        private static int LeftDigit(int rightDigit, ref int carryDigit, int n)
        {
            int nTimesRightDigitPlusCarryDigit = (rightDigit * n) + carryDigit;
            if (nTimesRightDigitPlusCarryDigit < 10)
            {
                carryDigit = 0;
                return nTimesRightDigitPlusCarryDigit;
            }
            else
            {
                carryDigit = 1;
                return nTimesRightDigitPlusCarryDigit % 10;
            }
        }

        public static long Smallest2ParasiticNumber(int onesPlaceValue)
        {
            return SmallestNParasiticNumber(onesPlaceValue, 2);
        }

        /// <remarks>
        /// An n-parasitic number (in base 10) is a positive natural number which
        /// can be multiplied by n by moving the rightmost digit of its decimal
        /// representation to the front.
        /// See Also: http://en.wikipedia.org/wiki/Parasitic_number
        /// </remarks>
        public static long SmallestNParasiticNumber(int onesPlaceValue, int n)
        {
            return DysonNumber(onesPlaceValue, n);
        }

        /// <remarks>
        /// The smallest n-parasitic numbers are also known as Dyson numbers, after
        /// a puzzle concerning these numbers posed by Freeman Dyson.
        /// See Also: http://en.wikipedia.org/wiki/Freeman_Dyson
        /// </remarks>
        public static long DysonNumber(int onesPlaceValue, int n)
        {
            #region Validate Parameters

            const string param1Name = "oncesPlaceValue";
            const string requirement1 = "onesPlaceValue must be an integer greater than oneand less than 10"; 
            if (onesPlaceValue < 2 || onesPlaceValue > 9)
            {
                throw new ArgumentException(requirement1, param1Name);
            }
            
            const string param2Name = "n";
            const string requirement2 = "n must be an integer greater than zero and less than 10";
            if (n < 1 || n > 9)
            {
                throw new ArgumentException(requirement2, param2Name);
            }
            
            #endregion

            int carryDigit = 0;
            int currentPlaceValue = onesPlaceValue;
            string parasiticNumberSuffix = onesPlaceValue.ToString();

            while (!NumberTester.Is2ParasiticNumber(long.Parse(parasiticNumberSuffix)))
            {
                currentPlaceValue = LeftDigit(currentPlaceValue, ref carryDigit, n);
                parasiticNumberSuffix = currentPlaceValue.ToString() + parasiticNumberSuffix;
            }

            return long.Parse(parasiticNumberSuffix);
        }
    }
}
